﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Text;

namespace Workflows.Components.TextMining.Collapse
{
    /// <summary>
    /// 
    /// </summary>
    public class SSNComparer:IAttributeComparer
    {
        #region settings
        private const int MaxAllowedTransposes = 1;
        private const int MaxAllowedIncrementals = 1;
        private SqlDbType _FieldDbType;
        #endregion

        #region IAttributeComparer Members

        /// <summary>
        /// specify either use code snippet or class
        /// </summary>
        public AttributeComparerType ComparerType
        {
            get
            {
                return AttributeComparerType.ClassComparer;
            }
        }

        public SqlDbType FieldDbType
        {
            get { return _FieldDbType; }
            set { _FieldDbType = value;}
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="value1"></param>
        /// <param name="value2"></param>
        /// <param name="penalty"></param>
        /// <param name="unevenDistTableName"></param>
        /// <returns></returns>
        public double Compare(object value1, object value2, double penalty, SqlConnection conn, string unevenDistTableName)
        {
            if (value1 == null || value2 == null || value1 == DBNull.Value || value2 == DBNull.Value)
                return 0.0;

            string ssn1 = value1.ToString();
            string ssn2 = value2.ToString();
            if(ssn1.Length==0 || ssn2.Length==0)
            {
                return 0.0;
            }
            else if (ssn1 == ssn2 && ssn1.Length==9)
            {
                return 10.00;
            }
            else if (ssn1 == ssn2)
            {
                return 1.00;
            }
            else
            {
                if(ssn1.Length==4 && ssn2.Length==9)
                {
                    if(ssn1==ssn2.Substring(5,4))
                    {
                        return 1.00;
                    }
                }
                else if(ssn1.Length==9 && ssn2.Length==4)
                {
                    if (ssn2 == ssn1.Substring(5, 4))
                    {
                        return 1.00;
                    }
                }
                char[] ssnChars1 = ssn1.ToCharArray();
                char[] ssnChars2 = ssn2.ToCharArray();
                List<int> mismatchedPositions=new List<int>();
                BitArray bits=new BitArray(Math.Min(ssn1.Length, ssn2.Length));
                bits.SetAll(true);
                for(int i=0;i<bits.Length;i++)
                {
                    if(ssnChars1[ssnChars1.Length - bits.Length +i]!=ssnChars2[ssnChars2.Length - bits.Length +i])
                    {
                        bits[i] = false;
                        mismatchedPositions.Add(i);
                    }
                }
                if(mismatchedPositions.Count==1)
                {
                    int digit1 = int.Parse(ssnChars1[ssnChars1.Length - bits.Length + mismatchedPositions[0]].ToString());
                    int digit2 = int.Parse(ssnChars2[ssnChars2.Length - bits.Length + mismatchedPositions[0]].ToString());
                    if(Math.Abs(digit2-digit1)==1)
                    {
                        return 0.75;
                    }
                    else
                    {
                        return 0.3;
                    }
                }
                else if(mismatchedPositions.Count==2)
                {
                    char firstChar1 = ssnChars1[ssnChars1.Length - bits.Length + mismatchedPositions[0]];
                    char firstChar2 = ssnChars2[ssnChars2.Length - bits.Length + mismatchedPositions[0]];
                    char secondChar1 = ssnChars1[ssnChars1.Length - bits.Length + mismatchedPositions[1]];
                    char secondChar2 = ssnChars2[ssnChars2.Length - bits.Length + mismatchedPositions[1]];
                    if (firstChar1 == secondChar2 && firstChar2 == secondChar1)
                        return 0.60;

                    int digitPosOffset11 = ssnChars1.Length - bits.Length + mismatchedPositions[0];
                    int digitPosOffset12 = ssnChars1.Length - bits.Length + mismatchedPositions[1];
                    int digitPosOffset21 = ssnChars2.Length - bits.Length + mismatchedPositions[0];
                    int digitPosOffset22 = ssnChars2.Length - bits.Length + mismatchedPositions[1];
                    if(digitPosOffset12-digitPosOffset11==1 && digitPosOffset22-digitPosOffset21==1)
                    {
                        int number1 = digitPosOffset11*10 + digitPosOffset12;
                        int number2 = digitPosOffset21*10 + digitPosOffset22;
                        if(Math.Abs(number2-number1)==1)
                        {
                            return 0.60;
                        }
                    }
                }
                return penalty;
            }
        }


        public object Merge(List<object> values, SqlConnection conn, string unevenDistTableName)
        {
            if (values == null || values.Count == 0)
                return null;

            Dictionary<string, int> countBySSN4 = new Dictionary<string, int>();
            Dictionary<string, int> countBySSN9 = new Dictionary<string, int>();
            foreach (object obj in values)
            {
                string ssn = obj.ToString();
                if (!string.IsNullOrEmpty(ssn) && ssn!="0000" && ssn!="000000000")
                {
                    if (ssn.Length == 9)
                    {
                        if (countBySSN9.ContainsKey(ssn))
                        {
                            countBySSN9[ssn] = countBySSN9[ssn] + 1;
                        }
                        else
                        {
                            countBySSN9.Add(ssn, 1);
                        }
                    }
                    else
                    {
                        if (countBySSN4.ContainsKey(ssn))
                        {
                            countBySSN4[ssn] = countBySSN4[ssn] + 1;
                        }
                        else
                        {
                            countBySSN4.Add(ssn, 1);
                        }
                    }
                }
            }

            // check ssn9 first
            if (countBySSN9.Count > 0)
            {
                if (countBySSN9.Count == 1)
                {
                    string[] ssns = new string[countBySSN9.Count];
                    countBySSN9.Keys.CopyTo(ssns, 0);
                    return ssns[0];
                }
                else
                {
                    string[] ssns = new string[countBySSN9.Count];
                    countBySSN9.Keys.CopyTo(ssns, 0);
                    string topSsnByCount = ssns[0];
                    for (int i = 1; i < countBySSN9.Count; i++)
                    {
                        string tmp = ssns[i];
                        if (countBySSN9[tmp] > countBySSN9[topSsnByCount])
                        {
                            topSsnByCount = tmp;
                        }
                    }
                    return topSsnByCount;
                }
            }
            else if (countBySSN4.Count > 0)
            {
                if (countBySSN4.Count == 1)
                {
                    string[] ssns = new string[countBySSN4.Count];
                    countBySSN4.Keys.CopyTo(ssns, 0);
                    return ssns[0];
                }
                else
                {
                    string[] ssns = new string[countBySSN4.Count];
                    countBySSN4.Keys.CopyTo(ssns, 0);
                    string topSsnByCount = ssns[0];
                    for (int i = 1; i < countBySSN4.Count; i++)
                    {
                        string tmp = ssns[i];
                        if (countBySSN4[tmp] > countBySSN4[topSsnByCount])
                        {
                            topSsnByCount = tmp;
                        }
                    }
                    return topSsnByCount;
                }
            }
            else
                return null;
            
        }
        #endregion

        #region dist frequency
        private int GetFrequencyForValue(SqlConnection conn, string distTableName, string fieldValue)
        {
            return 0;
        }
        #endregion
    }
}
